/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Windows Forms Controls Class Library
 * Version 2.00
 * 
 * Advanced Label Control Class
 *      An extension of the <see cref="System.Windows.Forms.Label"/> class with 
 * extended border styles, shadowing, and anti-aliasing capabilities.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.Text;
using System.ComponentModel;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Adaptive.Foundation.Windows.Forms
{
    /// <summary>
    /// An extension of the <see cref="System.Windows.Forms.Label"/> class with 
    /// extended border styles, shadowing, and anti-aliasing capabilities.
    /// </summary>
    [Browsable(true), DefaultProperty("Text"), DefaultEvent("Paint"), ToolboxItem(true), DesignerCategory("code"),
     Designer("System.Windows.Forms.Design.LabelDesigner, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"),
     ToolboxBitmap(typeof(EmbeddedResourceFinder), "Adaptive.Foundation.Windows.Forms.AdvancedLabel.bmp"),
     ClassInterface(ClassInterfaceType.AutoDispatch), 
     Description("Provides an advanced label control.")]
    public partial class AdvancedLabel : Label
    {
        /*-----------------------------------------------------------------m---------------
         * Public Event Definitions
         *------------------------------------------------------------------------------*/
        #region Public Event Definitions
        /// <summary>
        /// Occurs when the shadow value is changed.
        /// </summary>
        public event EventHandler ShadowChanged;
        /// <summary>
        /// Occurs when the anti-alias value is changed.
        /// </summary>
        public event EventHandler AntiAliasChanged;
        /// <summary>
        /// Occurs when the border style is changed.
        /// </summary>
        public event EventHandler BorderStyleChanged;
        
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Constants Declarations
         *------------------------------------------------------------------------------*/
        #region Private Constants Declarations
        /// <summary>
        /// Default text when label is first created.
        /// </summary>
        private const string DEFAULT_TEXT = "Adaptive Advanced Label";
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Member Declarations
         *------------------------------------------------------------------------------*/
        #region Private Member Declarations
        /// <summary>
        /// Text shadow flag.
        /// </summary>
        private bool _shadow = false;
        /// <summary>
        /// Text anti-aliasing flag.
        /// </summary>
        private bool _antiAlias = false;
        /// <summary>
        /// Shadow depth.
        /// </summary>
        private int _depth = 1;
        /// <summary>
        /// Border style.
        /// </summary>
        private AdvancedLabelBorderStyle _border = AdvancedLabelBorderStyle.None;
        #endregion

        /*--------------------------------------------------------------------------------
         * Constructor / Dispose / Destructor Methods
         *------------------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <remarks>
        /// This is the default constructor.
        /// </remarks>
        public AdvancedLabel()
            : base()
        {
            InitializeComponent();

            string[] rn = this.GetType().Assembly.GetManifestResourceNames();

            foreach (string s in rn)
            {

                System.Diagnostics.Trace.WriteLine(s);

            }


            //Set the Internal control styles to indicate owner drawn, and to use the
            //double-buffer technique.
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.CacheText, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            SetStyle(ControlStyles.UserPaint, true);
            DoubleBuffered = true;
 
            //This call is required by the Windows Form Designer.
            InitializeComponent();

            //Add any initialization after the InitializeComponent() call
            base.Text = DEFAULT_TEXT;
        }
        /// <summary>
        /// Deallocates internally allocated objects.
        /// </summary>
        /// <param name="disposing">
        /// A value indicating whether the object is being disposed.
        /// </param>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                    components.Dispose();
            }
            components = null;
            base.Dispose(disposing);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Properties
         *------------------------------------------------------------------------------*/
        #region Public Properties
        /// <summary>
        /// Gets or sets a flag for displaying shadowed text.
        /// </summary>
        /// <value>
        /// Set this property to <b>true</b> to display shadowed text; <b>false</b> for
        /// normal text.
        /// </value>
        [Browsable(true), Category("Appearance"), DefaultValue(false),
        Localizable(true),
        Description("Gets or sets a value indicating whether a shadow is displayed under the label text.")]
        public bool Shadow
        {
            get
            {
                return _shadow;
            }
            set
            {
                if (_shadow != value)
                {

                    _shadow = value;
                    OnShadowChanged(EventArgs.Empty);
                    Invalidate();
                }
            }
        }
        /// <summary>
        /// Gets or sets a flag to activate anti-aliasing on the label text.
        /// </summary>
        /// <value>
        /// <b>true</b> to apply anti-aliasing effects to the text; otherwise, 
        /// <b>false</b>.
        /// </value>
        [Browsable(true), Category("Appearance"), DefaultValue(false), Localizable(true),
        Description("Gets or sets a flag to activate anti-aliasing on the label text.")]
        public bool AntiAlias
        {
            get
            {
                return _antiAlias;
            }
            set
            {
                if (value != _antiAlias)
                {
                    _antiAlias = value;
                    OnAntiAliasChanged(EventArgs.Empty);
                    Invalidate();
                }
            }
        }
        /// <summary>
        /// Gets or sets the depth of the text shadow being displayed.
        /// </summary>
        /// <value>
        /// The size of the text shadow, in pixels.
        /// </value>
        [Browsable(true), Category("Appearance"), DefaultValue(1), Localizable(true),
        Description("Gets or sets the depth of the text shadow being displayed.")]
        public int ShadowDepth
        {
            get
            {
                return _depth;
            }
            set
            {
                _depth = value;
                Invalidate();
            }
        }
        /// <summary>
        /// Gets or sets the text of the label.
        /// </summary>
        /// <value>
        /// The text to be displayed in the label.
        /// </value>
        [Browsable(true), Category("Appearance"), DefaultValue("Adaptive Advanced Label"), Localizable(true),
        Description("Gets or sets the text of the label.")]
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                try
                {
                    base.Text = value;
                    Invalidate();
                }
                catch
                { }
            }
        }
        /// <summary>
        /// Gets or sets the border style for the label.
        /// </summary>
        /// <value>
        /// An <see cref="AdvancedLabelBorderStyle"/> enumerated value.
        /// </value>    
        [Browsable(true), Category("Appearance"),
        DefaultValue(AdvancedLabelBorderStyle.None), Localizable(true),
        Description("Gets or sets the border style for the label.")]
        public new AdvancedLabelBorderStyle BorderStyle
        {
            get
            {
                return _border;
            }
            set
            {
                if (value != _border)
                {
                    OnBorderStyleChanged(EventArgs.Empty);
                    _border = value;
                    Invalidate();
                }
            }
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Protected Methods / Event Methods
         *------------------------------------------------------------------------------*/
        #region Protected Methods / Event Methods
        /// <summary>
        /// Paints the background of the control.
        /// </summary>
        /// <param name="e">
        /// A <see cref="PaintEventArgs"/> event arguments object containing the 
        /// <see cref="Graphics"/> object used to paint the control.
        /// </param>
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            // Sets the background transparent so the parent container will paint the background.
            // Only paint if visible.
            if (Visible)
            {
                    base.OnPaintBackground(e);
            }
        }
        /// <summary>
        /// Renders the foreground of the label control.
        /// </summary>
        /// <param name="e">
        /// A <see cref="PaintEventArgs"/> event arguments object containing the 
        /// <see cref="Graphics"/> object used to paint the control.
        /// </param>
        protected override void OnPaint(PaintEventArgs e)
        {
            int count = 0;		//Iteration counter.
            Graphics g = e.Graphics;

            //Set anti-aliasing.
            SetAntiAliasMode(ref g);

            //Draw label shadows
            if (_shadow)
            {
                for (count = _depth; count > 0; count--)
                    DrawShadowText(e.Graphics, count);
            }

            //Draw Label Text
            RenderText(e.Graphics);

            //Draw Border Style
            RenderBorder(e.Graphics);
        }
        /// <summary>
        /// Re-draws the control when resized and raises the <see cref="Control.Resize"/> event.
        /// </summary>
        /// <param name="e">
        /// A <see cref="System.EventArgs"/> event arguments object.
        /// </param>
        protected override void OnResize(EventArgs e)
        {
            Invalidate();
            base.OnResize(e);
        }
        /// <summary>
        /// Raises the <see cref="ShadowChanged"/> event.
        /// </summary>
        /// <param name="e">
        /// An <see cref="EventArgs"/> event arguments instance.
        /// </param>
        protected virtual void OnShadowChanged(EventArgs e)
        {
            if (ShadowChanged != null)
                ShadowChanged(this, e);
        }
        /// <summary>
        /// Raises the <see cref="AntiAliasChanged"/> event.
        /// </summary>
        /// <param name="e">
        /// An <see cref="EventArgs"/> event arguments instance.
        /// </param>
        protected virtual void OnAntiAliasChanged(EventArgs e)
        {
            if (AntiAliasChanged != null)
                AntiAliasChanged(this, e);
        }
        /// <summary>
        /// Raises the <see cref="BorderStyleChanged"/> event.
        /// </summary>
        /// <param name="e">
        /// An <see cref="EventArgs"/> event arguments instance.
        /// </param>
        protected virtual void OnBorderStyleChanged(EventArgs e)
        {
            if (BorderStyleChanged != null)
                BorderStyleChanged(this, e);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Private Methods / Functions
        /// <summary>
        /// Draws the text shadow at the specified position.
        /// </summary>
        /// <param name="g">The Graphics object used for drawing.</param>
        /// <param name="offset">The distance from the actual text.</param>
        private void DrawShadowText(Graphics g, int offset)
        {
            SolidBrush brush;
            Point location;
            int alpha = 100;

            alpha = (100 - (20 * offset));
            if (alpha < 0)
                alpha = 0;

            location = GetTextPosition(g);
            brush = new SolidBrush(Color.FromArgb(alpha,
                    SystemColors.ControlDark.R,
                    SystemColors.ControlDark.G,
                    SystemColors.ControlDark.B));

            g.DrawString(Text, Font, brush, (location.X + offset), (location.Y + offset));
            brush.Dispose();
            brush = null;
        }
        /// <summary>
        /// Sets the anti-aliasing mode for the text.
        /// </summary>
        /// <param name="g">The Graphics object used for drawing.</param>
        private void SetAntiAliasMode(ref Graphics g)
        {
            if (_antiAlias)
            {
                g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
                g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                g.TextContrast = 1;
            }
            else
            {
                g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault;
            }
        }
        /// <summary>
        /// Renders the text of the label.
        /// </summary>
        /// <param name="g">The <see cref="Graphics"/> used to draw the control.</param>
        private void RenderText(Graphics g)
        {
            SolidBrush brush = null;
            Point textLoc;

            brush = new SolidBrush(ForeColor);
            textLoc = GetTextPosition(g);
            g.DrawString(Text, Font, brush, textLoc.X, textLoc.Y);
            brush.Dispose();
            brush = null;
        }
        /// <summary>
        /// Gets the position at which to begin drawing the label text.
        /// </summary>
        /// <param name="g">
        /// The <see cref="Graphics"/> object used to perform drawing tasks.
        /// </param>
        /// <returns>
        /// A <see cref="Point"/> structure containing the co-ordinates at which
        /// to begin drawing text.
        /// </returns>
        private Point GetTextPosition(Graphics g)
        {
            Point topLeft;
            SizeF size;

            size = g.MeasureString(Text, Font);
            topLeft = new Point(0, 0);

            switch (base.TextAlign)
            {
                case ContentAlignment.TopCenter:
                case ContentAlignment.TopLeft:
                case ContentAlignment.TopRight:
                    topLeft.Y = 0;
                    break;
                case ContentAlignment.BottomCenter:
                case ContentAlignment.BottomLeft:
                case ContentAlignment.BottomRight:
                    topLeft.Y = Height - (int)size.Height;
                    break;
                case ContentAlignment.MiddleCenter:
                case ContentAlignment.MiddleLeft:
                case ContentAlignment.MiddleRight:
                    topLeft.Y = (int)(((float)Height - size.Height) / 2);
                    break;
            }
            switch (base.TextAlign)
            {
                case ContentAlignment.BottomLeft:
                case ContentAlignment.MiddleLeft:
                case ContentAlignment.TopLeft:
                    topLeft.X = 0;
                    break;
                case ContentAlignment.TopRight:
                case ContentAlignment.BottomRight:
                case ContentAlignment.MiddleRight:
                    topLeft.X = Width - (int)size.Width;
                    break;
                case ContentAlignment.BottomCenter:
                case ContentAlignment.TopCenter:
                case ContentAlignment.MiddleCenter:
                    topLeft.X = (int)(((float)Width - size.Width) / 2);
                    break;
            }

            return topLeft;
        }
        /// <summary>
        /// Renders the label border according to the current style.
        /// </summary>
        /// <param name="g">
        /// The <see cref="Graphics"/> object used to perform drawing tasks.
        /// </param>
        private void RenderBorder(Graphics g)
        {
            switch (_border)
            {
                case AdvancedLabelBorderStyle.None:
                    break;
                case AdvancedLabelBorderStyle.ButtonBorder:
                    DrawButtonBorder(g);
                    break;
                case AdvancedLabelBorderStyle.InsetBox:
                    DrawBoxBorder(g, true);
                    break;
                case AdvancedLabelBorderStyle.InsetLine:
                    DrawLineBorder(g, true);
                    break;
                case AdvancedLabelBorderStyle.RaisedBox:
                    DrawBoxBorder(g, false);
                    break;
                case AdvancedLabelBorderStyle.RaisedLine:
                    DrawLineBorder(g, false);
                    break;
                case AdvancedLabelBorderStyle.SingleLine:
                    DrawSingleBorder(g);
                    break;
            }
        }
        /// <summary>
        /// Draws a button-style border around the label instance.
        /// </summary>
        /// <param name="g">
        /// The <see cref="Graphics"/> object used to perform drawing tasks.
        /// </param>
        private void DrawButtonBorder(Graphics g)
        {
            Pen penInstance = null;         //Pen pointer.
            int h = Height - 1;
            int w = Width - 1;

            penInstance = new Pen(SystemColors.ControlLightLight);
            g.DrawLine(penInstance, 0, 0, 0, h);
            g.DrawLine(penInstance, 0, 0, w, 0);

            penInstance = new Pen(SystemColors.ControlLight);
            g.DrawLine(penInstance, 1, 1, 1, h-2);
            g.DrawLine(penInstance, 1, 1, w-2, 1);

            penInstance = new Pen(SystemColors.ControlDarkDark);
            g.DrawLine(penInstance, 1, h, w, h);
            g.DrawLine(penInstance, w, h, w, 1);

            penInstance = new Pen(SystemColors.ControlDark);
            g.DrawLine(penInstance, 2, h-1, w-1, h-1);
            g.DrawLine(penInstance, w-1, h-1, w-1, 2);
        }
        /// <summary>
        /// Draws a box border.
        /// </summary>
        /// <param name="g">
        /// The <see cref="Graphics"/> object used to perform drawing tasks.
        /// </param>
        /// <param name="inset">
        /// A value indicating whether the box is inset or outset.
        /// </param>
        private void DrawBoxBorder(Graphics g, bool inset)
        {
            Pen topLeftPen = null;                  //Pen for drawing.
            Pen bottomRightPen = null;              //Pen for drawing.
            int h = Height - 1;
            int w = Width - 1;

            if (inset)
            {
                bottomRightPen = SystemPens.ControlLightLight;
                topLeftPen = SystemPens.ControlDark;
            }
            else
            {
                topLeftPen = SystemPens.ControlLightLight;
                bottomRightPen = SystemPens.ControlDark;
            }

            g.DrawLine(topLeftPen, 0, 0, 0, h);
            g.DrawLine(topLeftPen, 0, 0, w, 0);
            g.DrawLine(bottomRightPen, 1, h, w, h);
            g.DrawLine(bottomRightPen, w,h,w, 1);
        }
        /// <summary>
        /// Draws a line border.
        /// </summary>
        /// <param name="g">
        /// The <see cref="Graphics"/> object used to perform drawing tasks.
        /// </param>
        /// <param name="inset">
        /// A value indicating whether the line is inset or outset.
        /// </param>
        private void DrawLineBorder(Graphics g, bool inset)
        {
            Pen topLeftPen = null;                  //Pen for drawing.
            Pen bottomRightPen = null;              //Pen for drawing.

            if (inset)
            {
                bottomRightPen = SystemPens.ControlLightLight;
                topLeftPen = SystemPens.ControlDark;
            }
            else
            {
                topLeftPen = SystemPens.ControlLightLight;
                bottomRightPen = SystemPens.ControlDark;
            }

            //Create pen and draw line.
            g.DrawRectangle(topLeftPen, new Rectangle(0, 0, (Width - 2), (Height - 2)));
            g.DrawRectangle(bottomRightPen, new Rectangle(1, 1, (Width - 2), (Height - 2)));
        }
        /// <summary>
        /// Draws a border using the current control text color.
        /// </summary>
        /// <param name="g">
        /// The <see cref="Graphics"/> object used to perform drawing tasks.
        /// </param>
        private void DrawSingleBorder(Graphics g)
        {
            g.DrawRectangle(SystemPens.ControlText, new Rectangle(0, 0, (Width - 1), (Height - 1)));
        }
        #endregion

    }
}
